﻿using Devil;
using LitJson;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using UnityEngine;

namespace GameToolkit.UI
{
    public enum EDataType
    {
        Json,
        Xml,
    }

    public enum EUICompoiteState
    {
        Normal = 0,
        Selected = 1,
        Highlight = 2,
        Disabled = 4,
        Pressed = 8,
        Warning = 16,
    }

    public interface IUIInitializer
    {
        void OnInitialize(Object target);
    }

    public interface IUIRecursiveState
    {
        Object[] GetSkinComponents(GameObject root);
    }

    public interface IUITweener
    {
        void Activite(float duration);
        void Interrupt();
    }

    public interface IOverrideUISkin
    {
        bool IsOverrideSkin(Object context, string stateName);
    }

    public abstract class UITweenState
    {
        public readonly int id;
        public readonly string name;
        public UITweenState(string name)
        {
            this.name = name;
            this.id = name.IgnoreCaseToHash();
        }

        public UITweenState(int id)
        {
            this.id = id;
        }

        //public virtual UITweenState Clone(string stateName, XmlElement element)
        //{
        //    //var tname = element.Name;
        //    var v = element.InnerText.Trim();
        //    //if (string.IsNullOrEmpty(v))
        //    //    throw new System.Exception(string.Format("\"{0}\" 不能转换为\"{1}\"所需数据", element.InnerText, tname));
        //    return Clone(stateName, v);
        //}
        // trigger mode 不重复触发持续性的状态
        public virtual bool IsTriggerMode { get { return false; } }
        public abstract UITweenState Clone(string stateName, string content);
        public abstract UITweenState Clone(string stateName, JsonData data);
        public abstract Object GetSkinComponent(GameObject gameObject);
        public abstract IUITweener CreateSkin(Object target);
    }

    /// <summary>
    /// states: init, normal, highlight, selected, pressed, refused, disabled
    /// </summary>
    public partial class UISkinAsset
    {
        /**
         * <UI_SKIN>
         *      <STYLE name="">
         *          <highlight>
         *              <color> #ffffff </color>
         *              <scale> (1,1,1) </scale>
         *              <active> true </active>
         *              <sound> assets/.../xxx.wav </sound>
         *          </highlight>
         *          <selected></selected>
         *          <normal></normal>
         *          <pressed></pressed>
         *          <disabled></disabled>
         *          <refused></refused>
         *      </STYLE>
         *      
         *      <COMPOSITE name="componentName" style="" normal.scale="1" highlight.scale="1.2" >
         *          <item style="">
         *              <item style=""></item>
         *          </item>
         *      </COMPOSITE>
         * </UI_SKIN>
         */

        public static readonly Regex pattern_color = new Regex("^#[0-9a-fA-F]+$");
        public static readonly Regex pattern_number = new Regex("^(0.[0-9]+)|([1-9]+[0-9]*(.[0-9]+)?)$");
        public static readonly Regex pattern_style = new Regex(@"^(highlight|normal|pressed|disabled|refused|selected|warning|init)\.[a-zA-Z0-9_]+$");
        static readonly Regex pattern_default = new Regex(@"^(GLOBAL|(STYLE\..+))$");

        static readonly string cfg_STYLE = "STYLE";
        //static readonly string cfg_COMPOSITE = "COMPOSITE";
        static readonly string cfg_GLOBAL = "GLOBAL";

        //static readonly string att_name = "name";
        static readonly string att_style = "style";
        static readonly string att_recursive = "recursive";
        static readonly string att_selectable = "selectable";

        static readonly string stat_highlight = "highlight";
        static readonly string stat_normal = "normal";
        static readonly string stat_pressed = "pressed";
        static readonly string stat_disabled = "disabled";
        static readonly string stat_refused = "refused";
        static readonly string stat_selected = "selected";
        static readonly string stat_warning = "warning";
        static readonly string stat_init = "init";

        static readonly object sLock = new object();

        //static Dictionary<int, TweenGroup> sTweenCache = new Dictionary<int, TweenGroup>(16);
        //static List<CompositeItem> sItemCache = new List<CompositeItem>(16);

        static UISkinAsset sInstance;
        public static UISkinAsset SharedInstance
        {
            get
            {
                lock (sLock)
                {
                    if (sInstance == null)
                    {
                        sInstance = new UISkinAsset();
                    }
                    return sInstance;
                }
            }
        }

        public static void SetSharedInstance(UISkinAsset sharedInstance)
        {
            lock (sLock)
            {
                sInstance = sharedInstance;
            }
        }

        SortedList<UITweenState> mTweeners;
        SortedList<Composite> mComposites;
        readonly object mLock = new object();
        //int mLoadNum;

        public UISkinAsset()
        {
            mTweeners = new SortedList<UITweenState>(8, (x) => x.id);
            //mStyles = new SortedList<Style>(32, (x) => x.id);
            mComposites = new SortedList<Composite>(32, (x) => x.id);

            //mControllers = new RandomList<SkinController>(32);

            mTweeners.Add(new TweenColor());
            mTweeners.Add(new TweenAlpha());
            mTweeners.Add(new TweenScale());
            mTweeners.Add(new TweenActive());
            mTweeners.Add(new TweenCursor());
            mTweeners.Add(new TweenEffectColor());
            mTweeners.Add(new TweenIntensity());
        }

        public void AddTweener(UITweenState tweener)
        {
            mTweeners.Add(tweener);
        }

        public Composite GetComposite(int id)
        {
            return mComposites.GetValue(id);
        }

        public Composite GetComposite(string name)
        {
            return mComposites.GetValue(name.IgnoreCaseToHash());
        }

        public SkinController CreateSkinController(Transform root, int compositeId)
        {
            var com = mComposites.GetValue(compositeId);
            if (com != null)
                return new SkinController(com, root);
            return null;
        }

        public Composite CreateSkinComposite(string name, string config, EDataType dataType)
        {
            if (dataType == EDataType.Json)
            {
                var com = new Composite(name);
                var data = JsonMapper.ToObject(config);
                com.ReadData(this, null, null, null, null, data, null);
                return com;
            }
            else
            {
                throw new System.Exception("xml configuration for skin controller was not supported any more.");
            }
        }

        //public SkinController CreateSkinController(Transform root, string config, EDataType dataType)
        //{
        //    if (dataType == EDataType.Json)
        //    {
        //        var com = new Composite(root.name);
        //        var data = JsonMapper.ToObject(config);
        //        com.ReadData(this, null, null, null, null, data, null);
        //        return new SkinController(com, root);
        //    }
        //    else
        //    {
        //        throw new System.Exception("xml configuration for skin controller was not supported any more.");
        //    }
        //}

        public void LoadData(JsonData json)
        {
            Style globalStyle = null;
            SortedList<Style> styles = new SortedList<Style>(32, (x) => x.id);
            Dictionary<int, TweenGroup> tweenCache = new Dictionary<int, TweenGroup>();
            List<CompositeItem> itemCache = new List<CompositeItem>(8);
            var globaldata = json[cfg_GLOBAL];
            if (globaldata != null)
            {
                globalStyle = new Style("global");
                globalStyle.ReadData(this, globaldata, tweenCache);
            }
            foreach (var key in json.Keys)
            {
                if (pattern_default.IsMatch(key))
                    continue;
                var comp = new Composite(key);
                comp.ReadData(this, globalStyle, styles, itemCache, json, json[key], tweenCache);
                lock (mLock)
                {
                    mComposites.Add(comp, true);
                }
            }
            //#if UNITY_EDITOR
            //            Debug.Log("Load UISkin Complete: \n" + xmlContent);
            //#endif
        }

        //        public void LoadData(string xmlContent)
        //        {
        //            lock(mLock)
        //            {
        //                mLoadNum++;
        //            }
        //            var set = new XmlReaderSettings();
        //            set.CheckCharacters = false;
        //            var reader = XmlReader.Create(new StringReader(xmlContent), set);
        //            XmlDocument doc = new XmlDocument();
        //            doc.Load(reader);
        //            XmlNode child = doc.FirstChild;
        //            Style globalStyle = null;
        //            SortedList<Style> styles = new SortedList<Style>(32, (x) => x.id);
        //            Dictionary<int, TweenGroup> tweenCache = new Dictionary<int, TweenGroup>();
        //            List<CompositeItem> itemCacahe = new List<CompositeItem>(8);
        //            // Find Root Node
        //            while (child != null)
        //            {
        //                if (child.NodeType == XmlNodeType.Element && child.Name == "ROOT")
        //                {
        //                    child = child.FirstChild;
        //                    break;
        //                }
        //                child = child.NextSibling;
        //            }
        //            while (child != null)
        //            {
        //                if (child.NodeType == XmlNodeType.Element)
        //                {
        //                    if (child.Name == cfg_GLOBAL)
        //                    {
        //                        if (globalStyle == null)
        //                            globalStyle = new Style("global");
        //                        globalStyle.ReadData(this, (XmlElement)child, tweenCache);
        //                    }
        //                    else if (child.Name == cfg_STYLE)
        //                    {
        //                        var stname = ((XmlElement)child).GetAttribute(att_name);
        //                        var st = new Style(stname);
        //                        st.ReadData(this, (XmlElement)child, tweenCache);
        //                        styles.Add(st, true);
        //                    }
        //                    else if (child.Name == cfg_COMPOSITE)
        //                    {
        //                        var cname = ((XmlElement)child).GetAttribute(att_name);
        //                        var comp = new Composite(cname);
        //                        comp.ReadData(this, globalStyle, styles, itemCacahe, (XmlElement)child);
        //                        lock (mLock)
        //                        {
        //                            mComposites.Add(comp, true);
        //                        }
        //                    }
        //                }
        //                child = child.NextSibling;
        //            }

        //            lock (mLock)
        //            {
        //                mLoadNum--;
        //            }
        //#if UNITY_EDITOR
        //            Debug.Log("Load UISkin Complete: \n" + xmlContent);
        //#endif
        //        }

        internal class TweenGroup
        {
            public readonly UITweenState preset;
            public UITweenState normal;
            public UITweenState highlight;
            public UITweenState selected;
            public UITweenState disabled;
            public UITweenState pressed;
            public UITweenState refused;
            public UITweenState warning;
            public IUIInitializer initializer;

            public TweenGroup(UITweenState tweener)
            {
                this.preset = tweener;
            }

            public void CreateSkin(SkinController controller, CompositeItem item, GameObject target, ICollection<SkinGroup> skins)
            {
                if (target == null)
                    return;
                var overrider = target.GetComponentInParent<IOverrideUISkin>();
                if (item.recursive && (preset is IUIRecursiveState))
                {
                    var targets = ((IUIRecursiveState)preset).GetSkinComponents(target);
                    if (targets != null)
                    {
                        for (int i = 0; i < targets.Length; i++)
                        {
                            var obj = targets[i];
                            if (obj != null)
                            {
                                var skin = new SkinGroup(item, obj, overrider, this);
                                skins.Add(skin);
                            }
                        }
                    }
                    var rec = ComponentUtil.GetOrAddComponent<UISkinRecursive>(target);
                    if (rec != null)
                        rec.SetController(controller);
                }
                else
                {
                    var obj = preset.GetSkinComponent(target);
                    if (obj != null)
                    {
                        var skin = new SkinGroup(item, obj, overrider, this);
                        skins.Add(skin);
                    }
                }
            }

            internal void SetTweenStates(string statName, UITweenState stat)
            {
                if (statName == stat_normal)
                {
                    normal = stat;
                }
                else if (statName == stat_highlight)
                {
                    highlight = stat;
                }
                else if (statName == stat_selected)
                {
                    selected = stat;
                }
                else if (statName == stat_disabled)
                {
                    disabled = stat;
                }
                else if (statName == stat_refused)
                {
                    refused = stat;
                }
                else if (statName == stat_pressed)
                {
                    pressed = stat;
                }
                else if (statName == stat_warning)
                {
                    warning = stat;
                }
                else if (statName == stat_init)
                {
                    initializer = stat as IUIInitializer;
                }
                else
                {
                    throw new System.Exception(string.Format("无效的的状态({0})定义", statName));
                }
            }
        }


        public class Style
        {
            public readonly int id;
            public readonly string name;

            TweenGroup[] tweengroup;
            public int TweenCount { get { return tweengroup == null ? 0 : tweengroup.Length; } }
            public UITweenState GetTweenState(int index) { return tweengroup[index].preset; }

            internal Style(string name)
            {
                this.id = name.IgnoreCaseToHash();
                this.name = name;
            }

            internal Style(Dictionary<int, TweenGroup> overrides, Style style, Style defaultStyle)
            {
                if (style != null)
                {
                    id = style.id;
                    name = style.name;
                    MergeStyle(overrides, style);
                }
                if (defaultStyle != null)
                {
                    MergeStyle(overrides, defaultStyle);
                }

                tweengroup = new TweenGroup[overrides.Count];
                overrides.Values.CopyTo(tweengroup, 0);
            }

            void MergeStyle(Dictionary<int, TweenGroup> overrides, Style style)
            {
                if (style.tweengroup != null)
                {
                    for (int i = 0; i < style.tweengroup.Length; i++)
                    {
                        var sty = style.tweengroup[i];
                        TweenGroup grp;
                        if (overrides.TryGetValue(sty.preset.id, out grp))
                        {
                            if (grp.normal == null)
                                grp.normal = sty.normal;
                            if (grp.pressed == null)
                                grp.pressed = sty.pressed;
                            if (grp.highlight == null)
                                grp.highlight = sty.highlight;
                            if (grp.disabled == null)
                                grp.disabled = sty.disabled;
                            if (grp.refused == null)
                                grp.refused = sty.refused;
                            if (grp.selected == null)
                                grp.selected = sty.selected;
                            if (grp.warning == null)
                                grp.warning = sty.warning;
                            if (grp.initializer == null)
                                grp.initializer = sty.initializer;
                        }
                        else
                        {
                            overrides.Add(sty.preset.id, sty);
                        }
                    }
                }
            }

            internal void ReadData(UISkinAsset skinasset, JsonData data, Dictionary<int, TweenGroup> tweenCache)
            {
                if (tweenCache == null)
                    tweenCache = new Dictionary<int, TweenGroup>();
                tweenCache.Clear();
                TweenGroup grp;
                foreach (var key in data.Keys)
                {
                    var dot = key.IndexOf('.');
                    if (dot == -1)
                        throw new System.Exception(string.Format("无效的状态属性\"{0}\"", key));
                    var statName = key.Substring(0, dot);
                    var tname = key.Substring(dot + 1);
                    var id = tname.IgnoreCaseToHash();
                    var tweener = skinasset.mTweeners.GetValue(id);
                    if (tweener == null)
                        throw new System.Exception(string.Format("无效的状态属性\"{0}\"", key));
                    var stat = tweener.Clone(statName, data[key]);
                    if (stat != null)
                    {
                        if (!tweenCache.TryGetValue(tweener.id, out grp))
                        {
                            grp = new TweenGroup(tweener);
                            tweenCache[tweener.id] = grp;
                        }
                        grp.SetTweenStates(statName, stat);
                    }
                }
                int i = 0;
                tweengroup = new TweenGroup[tweenCache.Count];
                foreach (var t in tweenCache.Values)
                {
                    tweengroup[i++] = t;
                }
            }

            //internal void ReadData(UISkinAsset skinasset, XmlElement styleElement, Dictionary<int, TweenGroup> tweenCache)
            //{
            //    tweenCache.Clear();
            //    var child = styleElement.FirstChild;
            //    while (child != null)
            //    {
            //        if (child.NodeType == XmlNodeType.Element)
            //        {
            //            var tween = child.FirstChild;
            //            ReadTween(skinasset, child.Name, tween, tweenCache);
            //        }
            //        // next
            //        child = child.NextSibling;
            //    }
            //    int i = 0;
            //    tweengroup = new TweenGroup[tweenCache.Count];
            //    foreach (var t in tweenCache.Values)
            //    {
            //        tweengroup[i++] = t;
            //    }
            //}


            //void ReadTween(UISkinAsset skinasset, string statName, XmlNode first, Dictionary<int, TweenGroup> lst)
            //{
            //    XmlNode child = first;
            //    TweenGroup grp;
            //    while (child != null)
            //    {
            //        if (child.NodeType == XmlNodeType.Element)
            //        {
            //            var tname = child.Name;
            //            var id = StringUtil.IgnoreCaseToHash(tname);
            //            var tweener = skinasset.mTweeners.GetValue(id);
            //            if (tweener == null)
            //                throw new System.Exception(string.Format("无效的状态属性\"{0}\"", tname));
            //            var stat = tweener.Clone(statName, child as XmlElement);
            //            if (stat != null)
            //            {
            //                if (!lst.TryGetValue(tweener.id, out grp))
            //                {
            //                    grp = new TweenGroup(tweener);
            //                    lst[tweener.id] = grp;
            //                }
            //                grp.SetTweenStates(statName, stat);
            //            }
            //        }
            //        child = child.NextSibling as XmlElement;
            //    }
            //}

            internal void CreateSkinGroup(SkinController controller, CompositeItem item, GameObject gameObject, ICollection<SkinGroup> groups)
            {
                for (int i = 0; i < tweengroup.Length; i++)
                {
                    tweengroup[i].CreateSkin(controller, item, gameObject, groups);
                }
            }
        }

        public class CompositeItem
        {
            public readonly string path;
            public readonly Style style;
            public readonly bool recursive;
            public readonly bool alwaysSelectable;

            public CompositeItem(string path, Style style, bool recursive, bool alwaysSelectable)
            {
                this.path = path;
                this.style = style;
                this.recursive = recursive;
                this.alwaysSelectable = alwaysSelectable;
            }
        }

        public class Composite
        {
            public readonly int id;
            public readonly string name;

            CompositeItem[] items;
            int skinGroups;
            public int MaxSkinGroups { get { return skinGroups; } }

            public int Count { get { return items.Length; } }

            public CompositeItem this[int index] { get { return items[index]; } }

            internal Composite(string name)
            {
                this.name = name;
                this.id = name.IgnoreCaseToHash();
            }

            internal void ReadData(UISkinAsset skinasset, Style globalStyle, SortedList<Style> styles, List<CompositeItem> itemCache,
                JsonData fulldata, JsonData data, Dictionary<int, TweenGroup> cache)
            {
                if (itemCache == null)
                    itemCache = new List<CompositeItem>();
                else
                    itemCache.Clear();
                skinGroups = 0;
                ReadItem(skinasset, globalStyle, styles, fulldata, "", data, itemCache, cache);
                items = itemCache.ToArray();
            }

            Style GetStyle(UISkinAsset skinasset, string stylename, JsonData fulldata, SortedList<Style> styles, Dictionary<int, TweenGroup> cache)
            {
                var id = string.IsNullOrEmpty(stylename) ? 0 : stylename.IgnoreCaseToHash();
                var style = styles.GetValue(id);
                if (style == null && id != 0)
                {
                    style = new Style(stylename);
                    var stdata = fulldata == null ? null : fulldata[ParallelUtils.Concat(cfg_STYLE, '.', stylename)];
                    if (stdata == null)
                        throw new System.Exception(string.Format("没有找到风格配置\"STYLE.{0}\"(组件：{1})", stylename, name));
                    style.ReadData(skinasset, stdata, cache);
                    styles.Add(style);
                }
                return style;
            }

            void ReadItem(UISkinAsset skinasset, Style globalStyle, SortedList<Style> styles,
                JsonData fullData,
                string path, JsonData data,
                List<CompositeItem> lst, Dictionary<int, TweenGroup> cache)
            {
                Style currentStyle = null;
                Dictionary<int, TweenGroup> tweenGroups = null;
                if (data.IsObject)
                {
                    tweenGroups = new Dictionary<int, TweenGroup>(4);
                    foreach (var key in data.Keys)
                    {
                        if (currentStyle == null && key == att_style && styles != null)
                        {
                            var stylename = (string)data[key];
                            currentStyle = GetStyle(skinasset, stylename, fullData, styles, cache);
                        }
                        else if (pattern_style.IsMatch(key))
                        {
                            var n = key.IndexOf('.');
                            var statName = key.Substring(0, n);
                            var tweenName = key.Substring(n + 1);
                            var tweener = skinasset.mTweeners.GetValue(tweenName.IgnoreCaseToHash());
                            if (tweener == null)
                            {
                                //throw new System.Exception(string.Format("无效的状态属性\"{0}\"", tweenName));
                                Debug.LogError($"无效的状态属性\"{tweenName}\"");
                                continue;
                            }
                            var stat = tweener.Clone(statName, data[key]);
                            if (stat == null)
                                continue;
                            //if (tweenGroups == null)
                            //    tweenGroups = new Dictionary<int, TweenGroup>(4);
                            TweenGroup grp;
                            if (!tweenGroups.TryGetValue(tweener.id, out grp))
                            {
                                grp = new TweenGroup(tweener);
                                tweenGroups.Add(tweener.id, grp);
                            }
                            grp.SetTweenStates(statName, stat);
                        }
                        else if (key[0] == '/')
                        {
                            var root = string.IsNullOrEmpty(path) ? key.Substring(1) : ParallelUtils.Concat(path, '/', key.Substring(1));
                            ReadItem(skinasset, globalStyle, styles, fullData, root, data[key], lst, cache);
                        }
                    }
                }
                else
                {
                    currentStyle = GetStyle(skinasset, (string)data, fullData, styles, cache);
                }
                if (tweenGroups != null /*&& tweenGroups.Count > 0*/)
                {
                    currentStyle = new Style(tweenGroups, currentStyle, globalStyle);
                }
                if (currentStyle != null)
                {
                    var recur = (bool)data[att_recursive];// element.GetAttribute(att_recursive);
                    var sel = (bool)data[att_selectable]; //].GetAttribute(att_selectable);
                    var item = new CompositeItem(path, currentStyle, recur, sel);
                    lst.Add(item);
                    skinGroups += item.style.TweenCount;
                }
            }

            //void ReadItem(UISkinAsset skinAsset, Style globalStyle, SortedList<Style> styles, string path, XmlElement element, List<CompositeItem> lst)
            //{
            //    Style currentStyle = null;
            //    Dictionary<int,TweenGroup> tweenGroups = null;
            //    foreach (var item in element.Attributes)
            //    {
            //        XmlAttribute att = item as XmlAttribute;
            //        if (currentStyle == null && att.Name == att_style && styles != null)
            //        {
            //            currentStyle = string.IsNullOrEmpty(att.Value) ? null : styles.GetValue(StringUtil.IgnoreCaseToHash(att.Value));
            //        }
            //        else if (pattern_style.IsMatch(att.Name))
            //        {
            //            var n = att.Name.IndexOf('.');
            //            var statName = att.Name.Substring(0, n);
            //            var tweenName = att.Name.Substring(n + 1);
            //            var tweener = skinAsset.mTweeners.GetValue(StringUtil.IgnoreCaseToHash(tweenName));
            //            if (tweener == null)
            //                throw new System.Exception(string.Format("无效的状态属性\"{0}\"", tweenName));
            //            var stat = tweener.Clone(statName, att.Value);
            //            if (stat == null)
            //                continue;
            //            if (tweenGroups == null)
            //                tweenGroups = new Dictionary<int, TweenGroup>(4);
            //            TweenGroup grp;
            //            if (!tweenGroups.TryGetValue(tweener.id, out grp))
            //            {
            //                grp = new TweenGroup(tweener);
            //                tweenGroups.Add(tweener.id, grp);
            //            }
            //            grp.SetTweenStates(statName, stat);
            //        }
            //    }

            //    if (tweenGroups != null && tweenGroups.Count > 0)
            //    {
            //        currentStyle = new Style(tweenGroups, currentStyle, globalStyle);
            //    }
            //    if(currentStyle != null)
            //    {
            //        var recur = element.GetAttribute(att_recursive);
            //        var sel = element.GetAttribute(att_selectable);
            //        var item = new CompositeItem(path, currentStyle,
            //            StringUtil.EqualIgnoreCase(recur, "yes") || StringUtil.EqualIgnoreCase(recur, "true"),
            //            StringUtil.EqualIgnoreCase(sel, "yes") || StringUtil.EqualIgnoreCase(sel, "true"));
            //        lst.Add(item);
            //        skinGroups += item.style.TweenCount;
            //    }

            //    var child = element.FirstChild;
            //    while (child != null)
            //    {
            //        if (child.NodeType == XmlNodeType.Element)
            //        {
            //            var root = string.IsNullOrEmpty(path) ? child.Name : StringUtil.Concat(path, '/', child.Name);
            //            ReadItem(skinAsset, null, styles, root, child as XmlElement, lst);
            //        }
            //        child = child.NextSibling;
            //    }
            //}

            public void GetSkins(SkinController controller, Transform root, ICollection<SkinGroup> skins)
            {
                for (int i = 0; i < items.Length; i++)
                {
                    var item = items[i];
                    var trans = string.IsNullOrEmpty(item.path) ? root : root.Find(item.path);
                    if (trans != null)
                        item.style.CreateSkinGroup(controller, item, trans.gameObject, skins);
                }
            }

            public CompositeItem FindItem(string path)
            {
                if (items == null || items.Length < 1)
                    return null;
                if (string.IsNullOrEmpty(path))
                    return items[0];
                for (int i = 1; i < items.Length; i++)
                {
                    if (items[i].path == path)
                        return items[i];
                }
                return null;
            }
        }

        public class SkinGroup
        {

            //public readonly string path;
            public readonly int id;
            //internal readonly TweenGroup group;
            string name;
            Object target;
            IOverrideUISkin overrider;
            IUITweener normal;
            IUITweener highlight;
            IUITweener selected;
            IUITweener disabled;
            IUITweener pressed;
            IUITweener refused;
            IUITweener warning;
            IUIInitializer initializer;

            IUITweener current;
            bool alwaysSelectable;
            bool reset;
            bool isTrigger;
            EUICompoiteState finalState;

            internal SkinGroup(CompositeItem item, Object target, IOverrideUISkin overrider, TweenGroup group)
            {
                //this.path = item.path;
                //this.group = group;
                this.id = MathExt.Hash(target == null ? 0 : target.GetInstanceID(), group.preset.id);
                this.name = group.preset.name;
                this.target = target;
                this.overrider = overrider;
                if (group.normal != null)
                    normal = group.normal.CreateSkin(target);
                if (group.highlight != null)
                    highlight = group.highlight.CreateSkin(target);
                if (group.selected != null)
                    selected = group.selected.CreateSkin(target);
                if (group.disabled != null)
                    disabled = group.disabled.CreateSkin(target);
                if (group.pressed != null)
                    pressed = group.pressed.CreateSkin(target);
                if (group.refused != null)
                    refused = group.refused.CreateSkin(target);
                if (group.warning != null)
                    warning = group.warning.CreateSkin(target);
                initializer = group.initializer;
                this.alwaysSelectable = item.alwaysSelectable;
                this.isTrigger = group.preset.IsTriggerMode;
                reset = true;
            }

            IUITweener GetStateSkin(EUICompoiteState stat)
            {
                var diff = isTrigger ? ((stat ^ finalState) & stat) : stat;
                if ((stat & EUICompoiteState.Disabled) != 0)
                {
                    if (refused != null && (stat & EUICompoiteState.Pressed) != 0)
                        return refused;
                    var disable = disabled != null && (diff & EUICompoiteState.Disabled) != 0;
                    if (alwaysSelectable /*&& !disable*/)
                    {
                        if (highlight != null && (diff & EUICompoiteState.Highlight) != 0)
                            return highlight;
                        if (selected != null && (diff & EUICompoiteState.Selected) != 0)
                            return selected;
                    }
                    if (warning != null && (diff & EUICompoiteState.Warning) != 0)
                        return warning;
                    return disable ? disabled : normal;
                }
                if (pressed != null && (stat & EUICompoiteState.Pressed) != 0)
                    return pressed;
                if (highlight != null && (diff & EUICompoiteState.Highlight) != 0)
                    return highlight;
                if (selected != null && (diff & EUICompoiteState.Selected) != 0)
                    return selected;
                if (warning != null && (diff & EUICompoiteState.Warning) != 0)
                    return warning;
                return normal;
            }

            internal void Reset()
            {
                reset = true;
            }

            void Initialize()
            {
                if (reset && initializer != null && target != null)
                {
                    initializer.OnInitialize(target);
                    reset = false;
                }
            }

            public void Activite(EUICompoiteState state, float duration)
            {
                if (overrider != null && overrider.IsOverrideSkin(target, name))
                {
                    if (current != null)
                    {
                        current.Interrupt();
                        current = null;
                    }
                    reset = true;
                    return;
                }
                Initialize();
                var skin = GetStateSkin(state);
                finalState = state;
                if (skin == selected && current == skin)
                    return;
                if (skin != current && current != null)
                    current.Interrupt();
                current = skin;
                if (current != null)
                    current.Activite(duration);
            }

            public void Interrupt()
            {
                if (current != null)
                {
                    current.Interrupt();
                    current = null;
                }
            }
        }

        public class SkinController
        {
            public readonly Composite composite;
            public readonly Transform root;
            internal SortedList<SkinGroup> mSkins;
            EUICompoiteState mFinalState;

            public SkinController(Composite com, Transform root)
            {
                this.composite = com;
                this.root = root;
                mSkins = new SortedList<SkinGroup>(com.MaxSkinGroups, (sg) => sg.id);
                mSkins.ReplaceMode = true;
                com.GetSkins(this, root, mSkins);
            }

            public void Reset()
            {
                if (root != null)
                {
                    Release();
                    mSkins.Clear();
                    composite.GetSkins(this, root, mSkins);
                    if (mSkins != null)
                    {
                        for (int i = 0; i < mSkins.Count; i++)
                        {
                            mSkins[i].Reset();
                        }
                    }
                    if (mFinalState != 0)
                    {
                        Activite(mFinalState, 0);
                    }
                }
            }

            public void Activite(EUICompoiteState state, float duration)
            {
                if (mSkins != null)
                {
                    mFinalState = state;
                    for (int i = 0; i < mSkins.Count; i++)
                    {
                        mSkins[i].Activite(state, duration);
                    }
                }
            }

            public void Release()
            {
                mFinalState = 0;
                if (mSkins != null)
                {
                    for (int i = 0; i < mSkins.Count; i++)
                    {
                        mSkins[i].Interrupt();
                    }
                }
            }
        }
    }
}